/**
 * ============================================
 * 认证中间件模块
 *
 * 功能说明：
 * - 使用JWT（JSON Web Token）进行用户身份验证
 * - 保护需要登录才能访问的API接口
 * - 提供强制认证和可选认证两种模式
 * - 处理token过期、无效等错误情况
 *
 * JWT工作原理：
 * - JWT是一种安全的令牌标准，包含用户信息和签名
 * - 服务器签发token，客户端在请求头中携带token
 * - 服务器验证token签名和有效期，确保请求合法性
 *
 * 使用场景：
 * - authenticateToken: 必须登录的接口（如用户信息、交易操作）
 * - optionalAuthenticateToken: 可选的认证接口（如公开内容但显示个性化信息）
 * ============================================
 */

// 引入jsonwebtoken库 - 用于生成和验证JWT令牌
const jwt = require('jsonwebtoken');

/**
 * 强制认证中间件
 * 功能：验证JWT token，保护需要登录才能访问的接口
 * 工作流程：
 * 1. 从请求头中提取Authorization字段
 * 2. 检查token格式和存在性
 * 3. 验证token签名和有效期
 * 4. 将用户信息添加到req对象供后续使用
 * 5. 处理各种验证失败情况
 *
 * @param {Object} req - Express请求对象，包含请求头、参数等信息
 * @param {Object} res - Express响应对象，用于返回验证结果
 * @param {Function} next - Express下一个中间件函数，验证通过后调用
 * @returns {void} 通过next()继续或直接返回错误响应
 */
function authenticateToken(req, res, next) {
  /**
   * 从请求头中提取token
   * Authorization头格式：Bearer <token>
   * 示例：Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
   */
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1]; // 提取Bearer后面的token部分

  // 检查token是否存在 - 如果不存在则返回401未授权错误
  if (!token) {
    return res.status(401).json({
      status: 1,      // 状态码1表示错误
      msg: '需要认证token', // 错误消息
      data: null      // 错误时返回空数据
    });
  }

  try {
    /**
     * 验证JWT token
     * jwt.verify()方法会验证token的签名和有效期
     * 如果验证成功，返回解码后的payload（用户信息）
     * 密钥从环境变量JWT_SECRET获取，确保安全性
     */
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    
    /**
     * 将解码后的用户信息添加到请求对象中
     * 这样后续的中间件和路由处理函数可以直接使用req.user
     * 通常包含用户ID、用户名、角色等信息
     */
    req.user = decoded;
    
    // 验证通过，继续处理请求（调用下一个中间件或路由处理函数）
    next();
  } catch (error) {
    /**
     * token验证失败处理
     * 根据不同的错误类型返回相应的错误信息
     */
    if (error.name === 'TokenExpiredError') {
      // token已过期错误 - 返回401状态码
      return res.status(401).json({
        status: 1,
        msg: '认证令牌已过期', // 提示用户重新登录获取新token
        data: null
      });
    }
    
    // 其他token验证错误（如签名无效、格式错误等）- 返回403状态码
    return res.status(403).json({
      status: 1,
      msg: '无效的认证令牌', // 提示token格式或签名有问题
      data: null
    });
  }
}

/**
 * 可选认证中间件
 * 功能：如果请求提供了token就验证，没有提供就跳过认证
 * 使用场景：某些接口既支持匿名访问，也支持登录用户个性化访问
 * 特点：不会因为token缺失或无效而阻止请求，只会记录警告
 *
 * @param {Object} req - Express请求对象
 * @param {Object} res - Express响应对象
 * @param {Function} next - Express下一个中间件函数
 * @returns {void} 总是调用next()继续处理
 */
function optionalAuthenticateToken(req, res, next) {
  // 从Authorization头中提取token（格式同强制认证）
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];

  // 如果提供了token，尝试验证
  if (token) {
    try {
      // 验证token，如果成功则将用户信息添加到req对象
      const decoded = jwt.verify(token, process.env.JWT_SECRET);
      req.user = decoded;
    } catch (error) {
      /**
       * token验证失败，但不阻止请求继续
       * 只是记录警告日志，req.user保持undefined
       * 这样后续代码可以通过检查req.user是否存在来判断用户状态
       */
      console.warn('可选的token验证失败:', error.message);
    }
  }

  // 无论token验证结果如何，都继续处理请求
  next();
}

/**
 * ====================
 * 模块导出
 * ====================
 * 功能：导出两个认证中间件函数供其他模块使用
 * 在路由文件中通过require导入这些中间件
 */
module.exports = {
  authenticateToken,      // 强制认证中间件 - 必须提供有效token
  optionalAuthenticateToken // 可选认证中间件 - token可选提供
};